/*
 * Copyright (c) 2011-2020, baomidou (jobob@qq.com).
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * <p>
 * https://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.aabte.commons.rest.api;

import com.aabte.commons.rest.enums.StandardErrorCode;
import com.aabte.commons.rest.errorcode.IApiErrorCode;
import com.aabte.commons.rest.exception.ApiException;
import java.io.Serializable;
import java.util.Optional;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.experimental.Accessors;


/**
 * REST API 返回结果
 *
 * @author Daniel
 * @since 2020-04-05
 */
@Data
@Builder
@Accessors(chain = true)
@AllArgsConstructor
public class ApiResult<T> implements Serializable {

    /**
     * serialVersionUID
     */
    private static final long serialVersionUID = 1L;

    private String provider;

    /**
     * 业务错误码
     */
    private Long code;
    /**
     * 结果集
     */
    private T data;
    /**
     * 描述
     */
    private String msg;

    public ApiResult() {
        // to do nothing
    }

    public ApiResult(IApiErrorCode errorCode) {
        errorCode = Optional.ofNullable(errorCode).orElse(StandardErrorCode.InternalServerError);
        this.code = errorCode.getCode();
        this.msg = errorCode.getMsg();
    }

    public static <T> ApiResult<T> ok(T data) {
        StandardErrorCode aec = StandardErrorCode.OK;
        if (data instanceof Boolean && Boolean.FALSE.equals(data)) {
            aec = StandardErrorCode.InternalServerError;
        }
        return restResult(data, aec);
    }

    public static <T> ApiResult<T> failed(String msg) {
        return restResult(null, StandardErrorCode.InternalServerError.getCode(), msg);
    }

    public static <T> ApiResult<T> failed(IApiErrorCode errorCode) {
        return restResult(null, errorCode);
    }

    public static <T> ApiResult<T> failed(Long code, String msg) {
        return restResult(null, code, msg);
    }

    public static <T> ApiResult<T> failed(Long code, String msg, T data) {
        return restResult(data, code, msg);
    }

    public static <T> ApiResult<T> restResult(T data, IApiErrorCode errorCode) {
        return restResult(data, errorCode.getCode(), errorCode.getMsg());
    }

    private static <T> ApiResult<T> restResult(T data, Long code, String msg) {
        ApiResult<T> apiResult = new ApiResult<>();
        apiResult.setCode(code);
        apiResult.setData(data);
        apiResult.setMsg(msg);
        return apiResult;
    }

    public boolean ok() {
        return StandardErrorCode.OK.getCode().equals(code);
    }

    /**
     * 服务间调用非业务正常，异常直接释放
     */
    public T serviceData() {
        if (!ok()) {
            throw new ApiException(StandardErrorCode.InternalServerError.getStatus(), code,
                this.msg);
        }
        return data;
    }
}
